package ms.unicorn.erml.edit.policies;

import java.util.Iterator;
import java.util.List;

import ms.unicorn.Element;
import ms.unicorn.diagram.edit.parts.EntityEditPart;
import ms.unicorn.erml.ERML;
import ms.unicorn.modellanguage.HintedSpecializationType;
import ms.unicorn.modellanguage.LanguageRelation;
import ms.unicorn.util.LanguageUtil;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.IUndoableOperation;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.commands.DeferredCreateConnectionViewAndElementCommand;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewAndElementRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequestFactory;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.gmf.runtime.draw2d.ui.geometry.PointListUtilities;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.notation.View;

public class CompositionCreationEditPolicy extends GraphicalNodeEditPolicy{
	
	protected IElementType getElementType(CreateConnectionRequest request) {
		if (request instanceof CreateConnectionViewAndElementRequest) {
			CreateElementRequestAdapter requestAdapter = ((CreateConnectionViewAndElementRequest) request)
					.getConnectionViewAndElementDescriptor()
					.getCreateElementRequestAdapter();
			return (IElementType) requestAdapter.getAdapter(IElementType.class);
		}
		return null;
	}
	
	@Override
	protected Command getConnectionCompleteCommand(CreateConnectionRequest requestOrig) {
		CompoundCommand cc = new CompoundCommand(DiagramUIMessages.AddCommand_Label);
		Command origCommand = super.getConnectionCompleteCommand(requestOrig);
		IElementType etype = getElementType(requestOrig);
		LanguageRelation rel = null;
		
		if (etype instanceof HintedSpecializationType)
			rel = (LanguageRelation) ((HintedSpecializationType) etype).getElement();
		
		GraphicalEditPart srcEditPart = (GraphicalEditPart) requestOrig.getSourceEditPart();
		GraphicalEditPart tarEditPart = (GraphicalEditPart) requestOrig.getTargetEditPart();
		
		Element srcElement = (Element)(srcEditPart != null ? ViewUtil.resolveSemanticElement((View) srcEditPart.getModel()) : null);
		Element tarElement = (Element) (tarEditPart != null ? ViewUtil.resolveSemanticElement((View) tarEditPart.getModel()): null);
		
		if(rel != null && srcElement != tarElement 
				&& LanguageUtil.isCompability(srcElement, ERML.REQUIREMENT_ID) 
				&& LanguageUtil.isCompability(tarElement, ERML.REQUIREMENT_ID))
		{
			if(requestOrig.getType().equals(RequestConstants.REQ_CONNECTION_END))
			{
				cc.setLabel("terary");
				EntityEditPart sourceEditPart = (EntityEditPart)srcEditPart;
				EntityEditPart targetEditPart = (EntityEditPart)tarEditPart;
				
				// first- create the composition hub
				
				CreateViewAndElementRequest midHubRequest = (CreateViewAndElementRequest)
					CreateViewRequestFactory.getCreateShapeRequest(ERML.CompositionHub.getElementType(), null);

				Point sourceEndPoint = sourceEditPart.getPrimaryShape().getBounds().getTopLeft();
				sourceEditPart.getPrimaryShape().translateToAbsolute(sourceEndPoint);
				Point targetEndPoint = targetEditPart.getPrimaryShape().getBounds().getTopLeft();
				targetEditPart.getPrimaryShape().translateToAbsolute(targetEndPoint);
				
				Dimension sourceSize = new Dimension(sourceEditPart.getPrimaryShape().getBounds().getSize());
				Dimension targetSize = new Dimension(targetEditPart.getPrimaryShape().getBounds().getSize());

				Point sourceEndPointCenter = new Rectangle(sourceEndPoint, sourceSize).getCenter();
				Point targetEndPointCenter = new Rectangle(targetEndPoint, targetSize).getCenter();
				PointList list = new PointList();
				list.addPoint(sourceEndPointCenter);
				list.addPoint(targetEndPointCenter);
				
				int serviceWidth = 20;
				int serviceHeight = 20;
				
				Point middlePoint = PointListUtilities.calculatePointRelativeToLine(list, 0, 50, true);
				middlePoint.x -= serviceWidth/2;
				middlePoint.y -= serviceHeight/2;
				IAdaptable midHubAdaptable= (IAdaptable) ((List)midHubRequest.getNewObject()).get(0);

				midHubRequest.setLocation(middlePoint);
				
				Command midHubCommand = getHost().getParent().getCommand(midHubRequest);
				
				// create link from source to composition hub
				
				CreateConnectionViewAndElementRequest firstLinkRequest =  (CreateConnectionViewAndElementRequest)
					CreateViewRequestFactory.getCreateConnectionRequest
						(ERML.INSTANCE.getElementType(ERML.COMPOSITION_ID), null);

				
				DeferredCreateConnectionViewAndElementCommand firstLinkCommand = 
					new DeferredCreateConnectionViewAndElementCommand(firstLinkRequest, 
							(IAdaptable)ERML.Composition.getElementType(), 
							new EObjectAdapter(sourceEditPart.getPrimaryView()), 
							midHubAdaptable,
							getHost().getViewer());
				
				CreateConnectionViewAndElementRequest secondLinkRequest =  (CreateConnectionViewAndElementRequest)
					CreateViewRequestFactory.getCreateConnectionRequest
					(ERML.INSTANCE.getElementType(ERML.COMPOSITION_ID), null);
				
				
				
				
				DeferredCreateConnectionViewAndElementCommand secondLinkCommand = 
					new DeferredCreateConnectionViewAndElementCommand(secondLinkRequest, 
							(IAdaptable)ERML.Composition.getElementType(), 
							midHubAdaptable, 
							new EObjectAdapter(targetEditPart.getPrimaryView()),
							getHost().getViewer());
				
				cc.add(midHubCommand);
				
				Command firstLinkCommandWrapper =  new ICommandProxy(firstLinkCommand);
				Command secondLinkCommandWrapper =  new ICommandProxy(secondLinkCommand);
				
				cc.add(firstLinkCommandWrapper);
				cc.add(secondLinkCommandWrapper);
			}
		}
		else
			cc.add(origCommand);
		return cc;
	}

	
	@SuppressWarnings("rawtypes")
	@Override
	protected Command getConnectionAndRelationshipCompleteCommand(
			CreateConnectionViewAndElementRequest request) {
		// the semantic creation command is not necessary because the creation of semantic object
		// is taken care by create view composite command
		ICommandProxy cmd = (ICommandProxy) super.getConnectionAndRelationshipCompleteCommand(request);
		if (cmd != null && cmd.getICommand() instanceof CompositeCommand) {
			CompositeCommand icmd = (CompositeCommand) cmd.getICommand();
			
			Iterator iterator = icmd.iterator();
			ICommand semanticCmd =  (ICommand) iterator.next();
			ICommand createViewCmd = (ICommand) iterator.next();
			if (createViewCmd.getLabel().equals("terary"))
				icmd.remove((IUndoableOperation) semanticCmd);
		}
		return cmd;
	}
}
